package xin.codedream.codelog.web.controller.admin;

import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import xin.codedream.codelog.model.entity.Logs;
import xin.codedream.codelog.model.entity.User;
import xin.codedream.codelog.model.enums.ConstEnum;
import xin.codedream.codelog.model.enums.LoginStatusEnum;
import xin.codedream.codelog.model.enums.LogsEnum;
import xin.codedream.codelog.model.enums.ResponseEnum;
import xin.codedream.codelog.model.global.ResponseData;
import xin.codedream.codelog.service.ArticleService;
import xin.codedream.codelog.service.CommentService;
import xin.codedream.codelog.service.LogsService;
import xin.codedream.codelog.service.UserService;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Objects;

/**
 * 后台首页控制器
 *
 * @author NGLSL
 * @date 2018/8/4
 */
@Slf4j
@Controller
@RequestMapping("/admin")
public class AdminController {
    @Resource
    private UserService userService;
    @Resource
    private LogsService logsService;
    @Resource
    private ArticleService articleService;
    @Resource
    private CommentService commentService;
    private User user;
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    /**
     * 进入首页
     *
     * @return String
     */
    @GetMapping(value = {"", "/index"})
    public ModelAndView index() {
        ModelAndView mv = new ModelAndView("admin/admin_index");
        mv.addObject("user", user);
        return mv;
    }

    /**
     * 登录跳转
     *
     * @param session Session
     * @return String
     */
    @GetMapping("/login")
    public String login(HttpSession session) {
        User user = (User) session.getAttribute(ConstEnum.USER_SESSION_KEY.getValue());
        if (Objects.nonNull(user)) {
            return "redirect:/admin/index";
        }
        return "admin/admin_login";
    }

    /**
     * 登录执行
     *
     * @param userName 用户名
     * @param userPass 密码
     * @param session  Session
     * @param request  request
     * @return ResponseData
     */
    @PostMapping("/doLogin")
    @ResponseBody
    public ResponseData doLogin(String userName, String userPass,
                                HttpSession session, HttpServletRequest request) {
        ResponseData data = new ResponseData(ResponseEnum.LOGIN_ERROR);
        if (StringUtils.isEmpty(userName) || StringUtils.isEmpty(userPass)) {
            data.setCodeMessage(ResponseEnum.PARAM_EMPTY);
            saveLoginErrorLogs(userName, userPass, request);
            return data;
        }
        // 一般只有一个后台用户
        User info = userService.findUser();
        // 判断登录功能是否已经被禁用
        Date loginDate = DateUtil.date();
        if (Objects.nonNull(info.getLastLoginTime())) {
            loginDate = info.getLastLoginTime();
        }
        long between = DateUtil.between(loginDate, DateUtil.date(), DateUnit.MINUTE);
        if (Objects.equals(info.getLoginStatus(), LoginStatusEnum.LOGIN_DISABLE.getStatus())
                && (between < Long.parseLong(ConstEnum.LOGIN_DISABLE_TIME.getValue()))) {
            data.setCode(ResponseEnum.LOGIN_ERROR.getCode());
            data.setMessage("登录失败，请" + ConstEnum.LOGIN_DISABLE_TIME.getValue() + "分钟后再试");
            return data;
        }
        // 更新登录时间
        userService.updateLastLoginTime(info, DateUtil.date());
        User user = userService.userLoginByNameAndPass(userName, SecureUtil.md5(userPass));
        if (Objects.nonNull(user)) {
            this.user = user;
            // 重置登录状态
            user.setLoginError(-1);
            userService.updateLoginStatus(user, LoginStatusEnum.LOGIN_ENABLE.getStatus());
            userService.updateLoginError(user);
            logsService.saveLogInfo(new Logs(LogsEnum.TYPE_LOGIN_SUCCESS.getMessage(),
                    "用户：[" + HtmlUtil.escape(userName) + "]" + LogsEnum.TYPE_LOGIN_SUCCESS.getMessage(), ServletUtil.getClientIP(request)));

            session.setAttribute(ConstEnum.USER_SESSION_KEY.getValue(), user);
            data.setCodeMessage(ResponseEnum.LOGIN_SUCCESS);
            log.info("用户:{}，登录成功", user.getUserName());
            return data;
        } else {
            saveLoginErrorLogs(userName, userPass, request);
            int loginError = info.getLoginError() == null ? 0 : info.getLoginError();
            boolean loginErrorCount = loginError >=
                    Integer.parseInt(ConstEnum.LOGIN_ERROR_COUNT.getValue());
            if (loginErrorCount) {
                // 将用户登录功能状态禁用
                userService.updateLoginStatus(info, LoginStatusEnum.LOGIN_DISABLE.getStatus());
            } else {
                // 更新登录失败的错误次数
                userService.updateLoginError(info);
            }
            data.setCode(ResponseEnum.LOGIN_ERROR.getCode());
            data.setMessage("登录失败，您还剩下" + (Integer.parseInt(ConstEnum.LOGIN_ERROR_COUNT.getValue()) - loginError) + "次机会");
        }
        return data;
    }

    /**
     * 保存登录失败的日志信息
     *
     * @param userName 用户名
     * @param userPass 密码
     * @param request  request
     */
    private void saveLoginErrorLogs(String userName, String userPass,
                                    HttpServletRequest request) {
        logsService.saveLogInfo(new Logs(LogsEnum.TYPE_LOGIN_ERROR.getMessage(), "[尝试登录的用户信息：" +
                HtmlUtil.escape(userName) + "/" + HtmlUtil.escape(userPass) + "]", ServletUtil.getClientIP(request)));
    }

    /**
     * 退出登录
     *
     * @param session Session
     * @return String
     */
    @GetMapping("/logout")
    public String logout(HttpSession session, HttpServletRequest request) {
        User user = (User) session.getAttribute(ConstEnum.USER_SESSION_KEY.getValue());
        if (Objects.isNull(user)) {
            return "redirect:/admin/login";
        }
        logsService.saveLogInfo(new Logs(LogsEnum.TYPE_LOGOUT.getMessage(),
                "用户：[" + user.getUserName() + "]" + LogsEnum.TYPE_LOGOUT.getMessage(), ServletUtil.getClientIP(request)));
        log.info("用户:{}，退出成功", user.getUserName());
        session.invalidate();
        return "redirect:/admin/login";
    }

    /**
     * 加载WelCome页面
     *
     * @return String
     */
    @GetMapping("/adminWelcome")
    public ModelAndView welcome() {
        Calendar calendar = Calendar.getInstance();
        ModelAndView mv = new ModelAndView("admin/admin_welcome");
        mv.addObject("user", user);
        mv.addObject("currentDateTime", dateFormat.format(calendar.getTime()));
        mv.addObject("logs", logsService.findNewLogs());
        mv.addObject("allArticleQuantity", articleService.countAllArticleQuantity());
        mv.addObject("allCommentQuantity", commentService.countAllCommentQuantity());
        mv.addObject("fiveComment", commentService.findFiveComment());
        mv.addObject("fiveArticle", articleService.findFiveArticle());
        return mv;
    }
}
